package com.sinog.biz.schedule;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sinog.biz.config.ThreadPoolConfig;
import com.sinog.biz.mapper.havexml.AreaCodeFullMapper;
import com.sinog.biz.mapper.havexml.PrisonerMainMapper;
import com.sinog.biz.mapper.havexml.SystemCodeMapper;
import com.sinog.biz.util.MainUtil;
import com.sinog.core.utilbean.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;

/**
 * @desc 定时任务：1、定时生成行政区划四层拼接字符串表数据，用于excelsearchMap校验四层地址使用 2、定时重新生成用户部门缓存表 时间：每天凌晨5点25
 * @author lzq
 * @date 2021-09-20 00:02
 */
@Slf4j
@Component
@Configuration
public class AreaSchedule {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private PrisonerMainMapper prisonerMainMapper;
    @Autowired
    private SystemCodeMapper systemCodeMapper;
    @Autowired
    private AreaCodeFullMapper areaCodeFullMapper;
    @Autowired
    private ThreadPoolConfig threadPoolConfig;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 描述
     */
    @Scheduled(cron = "${gkzx.azbj.excel.fullArea.cron}")
    @Transactional(rollbackFor = Exception.class)
    public void executeDepartChild() {
        log.info("......任务1......");
        log.info("......开始生成行政区划四层拼接字符串表数据......");
        String areaDelSql = "delete from area_code_full where 1=1";
        String areaInsertSql = "INSERT INTO area_code_full (SELECT tc1.code_id AS sheng_code,tc2.code_id AS dishi_code,tc3.code_id AS quxian_code,tc4.code_id AS jiedao_code,tc1.code_name AS sheng_name,tc2.code_name AS dishi_name,tc3.code_name AS quxian_name,tc4.code_name AS jiedao_name,CONCAT( tc1.code_name, tc2.code_name, tc3.code_name, tc4.code_name ) AS fullname FROM tbsys_code tc1,tbsys_code tc2,tbsys_code tc3,tbsys_code tc4 WHERE tc1.code_id = tc2.pcode_id AND tc2.code_id = tc3.pcode_id AND tc3.code_id = tc4.pcode_id AND tc1.code_type = '2_1' AND length( tc2.code_id )> 4 ORDER BY tc1.code_id)";
        String areaInsertSql1 = "INSERT INTO area_code_full (SELECT tc1.code_id AS sheng_code,tc2.code_id AS dishi_code,tc3.code_id AS quxian_code,'' AS jiedao_code,tc1.code_name AS sheng_name,tc2.code_name AS dishi_name,tc3.code_name AS quxian_name,'' AS jiedao_name,CONCAT( tc1.code_name, tc2.code_name, tc3.code_name) AS fullname FROM tbsys_code tc1,tbsys_code tc2,tbsys_code tc3 WHERE tc1.code_id = tc2.pcode_id AND tc2.code_id = tc3.pcode_id AND tc3.code_id <> '-1' AND tc1.code_type = '2_1' and tc1.pcode_id = '-1' AND length( tc2.code_id )> 4 ORDER BY tc1.code_id)";
        jdbcTemplate.update(areaDelSql);
        jdbcTemplate.update(areaInsertSql);
        jdbcTemplate.update(areaInsertSql1);
        log.info("......生成行政区划四层拼接字符串表数据完毕......");
        log.info("......任务2......");
        log.info("初始化机构用户缓存表开始");
        String sql1 = "delete from tbsys_department_child_cache where 1=1";
        String sql2 = "delete from tbsys_user_child_cache where 1=1";
        String sql3 = "insert into tbsys_department_child_cache (id,childid) (select id,depart_getChilds_copy1(id) from tbsys_department)";
        String sql4 = "insert into tbsys_user_child_cache (id,childid) (SELECT id, depart_getChilds_copy1 (id) as childid from tbsys_department)";
        String sql5 = "INSERT INTO tbsys_department_child_cache(`id`, `childid`) VALUES ('-1', '$,100000,200000')";
        String sql6 = "insert INTO tbsys_user_child_cache (id,childid) VALUES ('-1','$,100000,200000')";
        String sql7 = "update tbsys_department_child_cache set childid=concat(childid,',')";
        String sql8 = "update tbsys_user_child_cache set childid=concat(childid,',')";
        jdbcTemplate.batchUpdate(sql1,sql2,sql3,sql4,sql5,sql6,sql7,sql8);
        log.info("初始化机构用户缓存表结束");
    }

    /**
     * 处理二次衔接中户籍地址变更的问题
     * 问题：
     * 监狱发起衔接信息，到户籍地址对应的司法所，司法所衔接失败，
     * 监狱上报到监狱局，监狱局上报司法厅，司法厅指定司法所
     * 监狱重新发起衔接，信息到司法厅指定的司法所，指定司法所衔接成功
     * 这时，如果不修改服刑人员的户籍地址，那么会出现，指定司法所衔接成功，数据却到了原户籍地址那了
     */
    //@Scheduled(cron = "${gkzx.azbj.excel.fullArea.cron}")
    public void executeSecondXjHuJiAddressChange() {
        log.info("......任务executeSecondXjHuJiAddressChange......start....");
        //查询xjxx表中有第二次司法所衔接信息的数据
        String hasSecondStreet = "select pri_num,second_province,second_city,second_county,second_street " +
                "from prisoner_xjxx " +
                "where second_province is not null and second_province !='' " +
                "and second_city is not null and second_city != '' " +
                "and second_county is not null and second_county != '' " +
                "and second_street is not null and second_street !='' ";
        //查询area_code_full和tbsys_code中有交集的行政区划
        String selectXzqh = "select concat(sheng_code,dishi_code,quxian_code,jiedao_code) from area_code_full acf " +
                "left join tbsys_code tc1 " +
                "on acf.sheng_code = tc1.code_id and tc1.code_type = '2_1' and tc1.pcode_id = '-1' " +
                "left join tbsys_code tc2 " +
                "on acf.dishi_code = tc2.code_id and tc2.code_type = '2_1' and acf.sheng_code = tc2.pcode_id " +
                "left join tbsys_code tc3 " +
                "on acf.quxian_code = tc3.code_id and tc3.code_type = '2_1' and acf.dishi_code = tc3.pcode_id " +
                "left join tbsys_code tc4 " +
                "on acf.jiedao_code = tc4.code_id and tc4.code_type = '2_1' and acf.quxian_code = tc4.pcode_id ";
        List<Map<String,Object>> secondStreetList = jdbcTemplate.queryForList(hasSecondStreet);
        List<String> list = jdbcTemplate.queryForList(selectXzqh,String.class);
        if(!secondStreetList.isEmpty()) {
            //循环遍历每条数据
            for(int i = 0; i < secondStreetList.size(); i++) {
                String priNum = (String)secondStreetList.get(i).get("pri_num");
                String province = (String)secondStreetList.get(i).get("second_province");
                String city = (String)secondStreetList.get(i).get("second_city");
                String county = (String)secondStreetList.get(i).get("second_county");
                String street = (String)secondStreetList.get(i).get("second_street");
                StringBuilder sb = new StringBuilder(province).append(city).append(county).append(street);
                //如果行政区划正确，则更改户籍地址
                if(null != list && list.contains(sb.toString())) {
                    String areaSql = "select * from area_code_full where sheng_code = '"+province+"' and dishi_code = '"+city+"' and quxian_code = '"+county+"' and jiedao_code = '"+street+"' limit 1;";
                    try {
                        Map<String,Object> areaMap = jdbcTemplate.queryForMap(areaSql);
                        String proName = (String)areaMap.get("sheng_name");
                        String cityName = (String)areaMap.get("dishi_name");
                        String countyName = (String)areaMap.get("quxian_name");
                        String villName = (String)areaMap.get("jiedao_name");
                        String sql = "update prisoner_main set nativepro = '" + province + "', nativecity = '" + city + "' ,nativecou = '" + county + "' ,nativevill = '" + street + "',nativepro_name = '"+proName+"',nativecity_name = '"+cityName+"' ,nativecou_name = '"+countyName+"',nativevill_name = '"+villName+"',update_user = 'executeSecondXjHuJiAddressChange()',update_time = now() where pri_num = " + priNum+" ;";
                        jdbcTemplate.execute(sql);
                        log.info("......更改数据成功:pri_num = "+priNum+"....");
                    } catch(DataAccessException e) {
                        log.error("......修改数据失败:pri_num = "+priNum+"....");
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        log.info("......任务executeSecondXjHuJiAddressChange......end....");
        log.info("初始化机构用户缓存表结束");
    }

    /**
     * 更新死数据列表行政区划编码为汉字的情况，经排查，很多死数据是由于行政区划编码变成了汉字，然后导致司法四层看不见
     */
    @Scheduled(cron = "${gkzx.azbj.excel.fullArea.cron}")
    public void updateSsjList() {
        Page<Map<String,String>> page = new Page<>(1,50);
        page.setSearchCount(false);
        Long ssjListCount = prisonerMainMapper.getSsjListCount(page,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
        page.setCurrent(1);
        page.setSize(ssjListCount);
        //获取脏数据列表
        List<Map<String,String>> ssjList = prisonerMainMapper.getSsjList(page,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
        int size;
        if(ssjList.size() > 500) {
            size = 500;
        }else {
            size = ssjList.size();
        }
        CountDownLatch countDownLatch = new CountDownLatch(size);
        //遍历列表信息
        for(Map<String,String> map : ssjList) {
            CompletableFuture.supplyAsync(new Supplier<Object>() {
            })

            threadPoolConfig.taskExecutor().execute(()->{
                try {
                    log.info("线程:{},开始异步处理:{}",Thread.currentThread().getName(),map.get("pname"));
                    String nativePro = map.get("nativepro");
                    String nativeCity = map.get("nativecity");
                    String nativeCou = map.get("nativecou");
                    String nativeVill = map.get("nativevill");
                    String prinum = map.get("prinum");
                    //如果省编码不为空，且省份编码为中文，转换为编码
                    if(StringUtils.isNotBlank(nativePro) && !MainUtil.isNumber(nativePro)) {
                        nativePro = systemCodeMapper.getCodeIdByCodeName(nativePro,Constants.NumberStr.NUM_STR_FU_ONE);
                    }
                    //如果地市编码不为空，且省份编码为中文，转换为编码
                    if(StringUtils.isNotBlank(nativeCity) && !MainUtil.isNumber(nativeCity)) {
                        nativeCity = systemCodeMapper.getCodeIdByCodeName(nativeCity,nativePro);
                    }
                    //如果区县编码不为空，且省份编码为中文，转换为编码
                    if(StringUtils.isNotBlank(nativeCou) && !MainUtil.isNumber(nativeCou)) {
                        nativeCou = systemCodeMapper.getCodeIdByCodeName(nativeCou,nativeCity);
                    }
                    //如果街道编码不为空，且省份编码为中文，转换为编码
                    if(StringUtils.isNotBlank(nativeVill) && !MainUtil.isNumber(nativeVill)) {
                        nativeVill = systemCodeMapper.getCodeIdByCodeName(nativeVill,nativeCou);
                    }
                    if(StringUtils.isNotBlank(nativePro) && StringUtils.isNotBlank(nativeCity) && StringUtils.isNotBlank(nativeCou)) {
                        //根据行政区划编码查询行政区划名称
                        Map<String,String> areaNames = areaCodeFullMapper.getAreaNames(nativePro,nativeCity,nativeCou,nativeVill);
                        if(null != areaNames) {
                            String proName = areaNames.get("shengName");
                            String cityName = areaNames.get("dishiName");
                            String couName = areaNames.get("quxianName");
                            String villName = areaNames.get("jiedaoName");
                            if(Constants.SpecialChar.NUM_BLANK.equals(nativeVill)) {
                                villName = "";
                            }
                            //根据罪犯编号更新行政区划信息
                            int save = prisonerMainMapper.updateAreaCodeByPriNum(prinum,nativePro,nativeCity,nativeCou,nativeVill,proName,cityName,couName,villName);
                            if(Constants.Number.NUM_ONE.equals(save)) {
                                log.info("线程:{},更新数据成功:{}",Thread.currentThread().getName(),map.get("pname"));
                            }else {
                                log.error("线程:{},脏数据列表行政区划更改保存失败...{}",Thread.currentThread().getName(),map.get("pname"));
                            }
                        }
                    }
                } catch(Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch(InterruptedException e) {
            log.error("发生异常{}",e.getMessage());
        }
    }

    /**
     * 定时-补偿redis中的areaCode和areaCodeAndPcode
     */
    @Scheduled(cron = "${gkzx.azbj.excel.fullArea.cron}")
    @Transactional(rollbackFor = Exception.class)
    public void timingReplenishRedisArea(){
        timingAreaCode();
        timingAreaCodeAndPcode();
    }

    /**
     * 定时-补偿areaCode
     */
    public void timingAreaCode(){
        log.info(">>>>>>>>>>开始同步areaCode:redis<<<<<<<<<<");
        RedisSerializer<String> serializer = new StringRedisSerializer();
        stringRedisTemplate.setKeySerializer(serializer);
        stringRedisTemplate.setValueSerializer(serializer);
        stringRedisTemplate.setHashKeySerializer(serializer);
        stringRedisTemplate.setHashValueSerializer(serializer);
        //查询系统中tbsys_code表全部code_id和code_name
        List<Map<String,Object>> lists = systemCodeMapper.getCodeIdAndName(Constants.CodeType.CODE_ZHRMGHG_XZQH_DM);
        Map<String, String> maps = new HashMap<>(16);
        for(Map<String,Object> stringObjectMap : lists) {
            maps.put(stringObjectMap.get("codeId").toString(),stringObjectMap.get("codeName").toString());
        }
        stringRedisTemplate.opsForHash().putAll("areaCode",maps);
        log.info(">>>>>>>>>>结束同步areaCode:redis<<<<<<<<<<");
    }

    /**
     * 定时-补偿areaCodeAndPcode
     */
    public void timingAreaCodeAndPcode(){
        log.info(">>>>>>>>>>开始同步{}:redis<<<<<<<<<<","areaCodeAndPcode");
        RedisSerializer<String> serializer = new StringRedisSerializer();
        stringRedisTemplate.setKeySerializer(serializer);
        stringRedisTemplate.setValueSerializer(serializer);
        stringRedisTemplate.setHashKeySerializer(serializer);
        stringRedisTemplate.setHashValueSerializer(serializer);
        //查询系统中tbsys_code表全部code_id和code_name
        List<Map<String,Object>> lists = systemCodeMapper.getAreaCodeAndPcode();
        Map<String, String> maps = new HashMap<>(16);
        for(Map<String,Object> stringObjectMap : lists) {
            maps.put(stringObjectMap.get("codeId").toString(),stringObjectMap.get("pCode").toString());
        }
        stringRedisTemplate.opsForHash().putAll("areaCodeAndPcode",maps);
        log.info(">>>>>>>>>>结束同步{}:redis<<<<<<<<<<","areaCodeAndPcode");
    }
}